package com.alibaba.it.asset.codegen.db2entity;

import com.alibaba.it.asset.codegen.db2entity.processor.EntityGenerater;
import com.alibaba.it.asset.codegen.db2entity.processor.MapGenerater;
import com.alibaba.it.asset.codegen.db2entity.processor.RepositoryGenerater;
import com.alibaba.it.asset.codegen.db2entity.processor.ServiceGenerater;
import com.alibaba.it.asset.codegen.db2entity.vo.DBColumnVO;
import com.alibaba.it.asset.codegen.db2entity.vo.PrimaryKeyColumnVO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.ResultSet;
import java.util.*;

/**
 * 从数据库生成实体的工具类
 */
public class DB2EntityUtil {

    private String connectionURL = PropertyUtil.getProperty("jdbc.url");

    private String username = PropertyUtil.getProperty("jdbc.username");

    private String password = PropertyUtil.getProperty("jdbc.password");

    private static String genPath = PropertyUtil.getProperty("gen.path");
    private static String entityPackage = PropertyUtil.getProperty("gen.entity.package");
    private static String repositoryPackage = PropertyUtil.getProperty("gen.repository.package");
    private static String servicePackage = PropertyUtil.getProperty("gen.service.package");

    private Connection conn;

    private Class driveClass;

    private static DB2EntityUtil util = new DB2EntityUtil();

    public void init(Class driveClass) {
        this.driveClass = driveClass;
        // this.connectionURL = connectionURL;
        // this.username = username;
        // this.password = password;
        // this.driveClass = driveClass;
    }

    public void init(Class driveClass,
                     String connectionURL, String username, String password) {
        this.driveClass = driveClass;
        this.connectionURL = connectionURL;
        this.username = username;
        this.password = password;
        this.driveClass = driveClass;
    }

    public static DB2EntityUtil getDB2EntityUtil() {
        return util;
    }

    private DB2EntityUtil() {

    }

    public void refreshDriver(String urlPath, String jdbcDriver) throws ClassNotFoundException {
        driveClass = DBClassLoaderUtil.getCURDClassLoader(urlPath).forName(jdbcDriver);
    }

    public void connect() throws Exception {
        Driver driver = (Driver) driveClass.newInstance();
        Properties p = new Properties();
        p.put("user", username);
        p.put("password", password);
        conn = driver.connect(connectionURL, p);
    }

    public void closeConn() throws Exception {
        if (conn != null) {
            conn.close();
        }
    }

    public List<DBColumnVO> getColumns(String tableName) throws Exception {

        ResultSet rs;
        List<DBColumnVO> columns = new ArrayList<DBColumnVO>();
        DatabaseMetaData metaData = conn.getMetaData();

        // 查询主键
        rs = metaData.getPrimaryKeys(null, null, tableName);
        Map<String, PrimaryKeyColumnVO> primaryKeys = new HashMap<String, PrimaryKeyColumnVO>();

        while (rs.next()) {
            PrimaryKeyColumnVO vo = new PrimaryKeyColumnVO();
            vo.setPrimarySeq(rs.getInt("KEY_SEQ"));
            vo.setPkName(rs.getString("PK_NAME"));

            primaryKeys.put(rs.getString("COLUMN_NAME"), vo);
        }

        rs = metaData.getColumns(null, null, tableName, null);
        while (rs.next()) {

            String columnName = rs.getString("COLUMN_NAME");
            DBColumnVO vo;
            if (primaryKeys.containsKey(columnName)) {
                vo = primaryKeys.get(columnName);
                ((PrimaryKeyColumnVO) vo).setAutoIncrement(rs.getString(
                        "IS_AUTOINCREMENT").equals("YES"));
            } else {
                vo = new DBColumnVO();
            }
            vo.setColumnName(columnName);
            vo.setDataType(rs.getInt("DATA_TYPE"));
            vo.setRemarks(rs.getString("REMARKS"));
            vo.setTypeName(rs.getString("TYPE_NAME"));
            columns.add(vo);
        }
        return columns;
    }

    /**
     * 获取数据库下的所有表
     *
     * @return
     * @throws Exception
     */
    public List<String> getTables() throws Exception {
        List<String> tables = new ArrayList<String>();
        ResultSet rs = null;
        DatabaseMetaData metaData = conn.getMetaData();
        if (isOracle()) {
            rs = metaData.getTables(null, username.toUpperCase(), null, new String[]{"TABLE"});
        } else {
            rs = metaData.getTables(null, null, null, new String[]{"TABLE"});
        }
        while (rs.next()) {
            String tableName = rs.getString("TABLE_NAME");
            tables.add(tableName);
        }
        return tables;
    }

    private boolean isOracle() {
        return connectionURL.startsWith("jdbc:oracle");
    }

    public static void main(String[] args) throws Exception {
        Map<String, String> tableMaps = Maps.newHashMap();
//        tableMaps.put("auto_send_order_strategy", "AutoSendOrderStrategy");
//        tableMaps.put("channel", "Channel");
//        tableMaps.put("channel_production", "ChannelProduction");
//        tableMaps.put("collection_admin", "CollectionAdmin");
//        tableMaps.put("collection_order", "CollectionOrder");
//        tableMaps.put("collection_order_receive", "CollectionOrderReceive");
//        tableMaps.put("collection_work_progress", "CollectionWorkProgress");
        tableMaps.put("payment_collection_record", "PaymentCollectionRecord");
//        tableMaps.put("payment_offline_record", "PaymentOfflineRecord");
//        tableMaps.put("reduction_application", "ReductionApplication");
//        tableMaps.put("reduction_record", "ReductionRecord");
//        tableMaps.put("strategy_collector_rel", "StrategyCollectorRel");
//        tableMaps.put("strategy_production_rel", "StrategyProductionRel");
//        tableMaps.put("sys_enum_dict", "SysEnumDict");
//        tableMaps.put("sys_dict", "SysDict");
//        tableMaps.put("channel_config", "ChannelConfig");

        // 实体生产
        List<GenerateProcessor> processors = Lists.newArrayList();
        processors.add(new EntityGenerater());      // dto
        //  processors.add(new RepositoryGenerater()); // dao
        //  processors.add(new MapGenerater());        // mapping.xml
        //  processors.add(new ServiceGenerater());  // service

        process(tableMaps, processors, true);
    }

    private static void process(Map<String, String> tableMaps, List<GenerateProcessor> processors, boolean overwrite) throws Exception {
        DB2EntityUtil util = DB2EntityUtil.getDB2EntityUtil();

        util.init(com.mysql.jdbc.Driver.class);
        util.connect();

        GenerateContext.Builder builder = GenerateContext.newBuilder();
        builder.genPath(genPath)
                .entityPackage(entityPackage)
                .repositoryPackage(repositoryPackage)
                .servicePackage(servicePackage)
                .overwrite(overwrite);
        for (GenerateProcessor processor : processors) {
            for (Map.Entry<String, String> entry : tableMaps.entrySet()) {
                processor.process(builder.build(), entry.getKey(), entry.getValue(), util.getColumns(entry.getKey()));
            }
        }
        util.closeConn();
    }
}
